﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml.Input;
using Controls = Windows.UI.Xaml.Controls;
using Shapes = Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Media;
using Windows.UI;
using Windows.UI.Xaml.Controls;
using BoolanSlide.ElementMenu;
using Windows.UI.Xaml;
using Windows.Foundation;
using Windows.UI.Xaml.Shapes;
using Configuration;
using BoolanSlide.RedoUndo;
using Windows.UI.Xaml.Media.Imaging;
using BoolanSlide.Language;

namespace BoolanElement
{
    public class BooCurve : BooLineBase, IFocusEllOperation, ILineStyleController
    {
        public Shapes.Polyline Curve;
        public Shapes.Polyline FindCurve;
        public Canvas CenterEllipse;
        Point centerPoint;
        ControlPanel lineControlPanel;
        TranslateTransform topT;
        TranslateTransform bottomT;
        BooCurveElement curveElement;
        public BooCurveElement CurveElement
        {
            get
            {
                return curveElement;
            }
        }

        LineMenu curveMenu;
        public LineMenu LineMenu
        {
            get { return curveMenu; }
        }

        public override MenuBase UIMenu
        {
            get { return curveMenu; }
        }


        public override BooElement Element
        {
            set { curveElement = (BooCurveElement)value; }
            get { return curveElement; }
        }


        public BooCurve(BooCurveElement element,SaveForRedoUndo saveForRedoUndo):base(element)
        {
            this.curveElement = element;
            InitOriginal();
            Focus.InitFocusEvent(this);
            topT = new TranslateTransform();
            bottomT = new TranslateTransform();
            Focus.FocusElls.left_top_ell.RenderTransform = topT;
            Focus.FocusElls.right_bottom_ell.RenderTransform = bottomT;
            InitLineControlPanel();
            InitContextMenu();
            base.saveForRedoUndo = saveForRedoUndo;
            LostFocus();
            LanguageManager.LanguageChanged += LanguageManager_LanguageChanged;
        }

        void LanguageManager_LanguageChanged(object sender)
        {
            lineControlPanel.ModifyTab(LanguageManager.StyleTabNormal2, LanguageManager.StyleTabDown2, LanguageManager.StyleTabDown2, 0);
        }

        public override void BooLineBaseElement_ShapePropertyChanged(object sender, BoolanSlide.UIElement.Shapes.TextShapes.Common.ShapePropertyChangedArgs args)
        {
            base.BooLineBaseElement_ShapePropertyChanged(sender, args);
        }

        public BooCurve(BooCurveElement element):base(element)
        {
            this.curveElement = element;
            InitForThumbNails();
        }

        void InitOriginal()
        {
            CreateShape();
            InitializeActionMap(BooCanvas);
            InitContextMenu();
            Focus.InsertFocusEllipses(BooCanvas);
            Focus.FocusElls.left_top_ell.Margin = new Thickness(this.curveElement.Point1.X - FocusEllipses.FocusTouchAreaLength / 2,
               this.curveElement.Point1.Y - FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
            Focus.FocusElls.right_bottom_ell.Margin = new Thickness(this.curveElement.Point3.X - FocusEllipses.FocusTouchAreaLength / 2,
                this.curveElement.Point3.Y - FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
        }

        void InitForThumbNails()
        {
            CreateShape();
            ApplyTransform(BooCanvas);
            BooCanvas.ManipulationMode = ManipulationModes.All;
        }

        void InitContextMenu()
        {
            curveMenu = new LineMenu(this);
        }

        void CreateShape()
        {
            InitLine();
            centerPoint = InitBezierLine(Curve,this.curveElement.Point1,this.curveElement.Point2,this.curveElement.Point3);
            InitFindCurve();
            InitCanvas();
            BooCanvas.Children.Add(FindCurve);
            BooCanvas.Children.Add(Curve);

            SolidColorBrush fillColor = new SolidColorBrush(ConstColor.TitleColor);
            SolidColorBrush strokeColor = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));

            CenterEllipse = new Canvas();
            CenterEllipse.Width = FocusEllipses.FocusTouchAreaLength;
            CenterEllipse.Height = FocusEllipses.FocusTouchAreaLength;
            CenterEllipse.Background = new SolidColorBrush(Colors.Transparent);
            Ellipse CenterEllipseVisual = new Ellipse();
            CenterEllipseVisual.Width = FocusEllipses.FocusEllipsesDiameter;
            CenterEllipseVisual.Height = FocusEllipses.FocusEllipsesDiameter;
            CenterEllipseVisual.Fill = fillColor;
            CenterEllipseVisual.Stroke = strokeColor;
            CenterEllipseVisual.Margin = new Thickness((CenterEllipse.Width-CenterEllipseVisual.Width)/2,(CenterEllipse.Height-CenterEllipseVisual.Height)/2,0,0);

            CenterEllipse.Margin = new Thickness(centerPoint.X - CenterEllipse.Width/2, centerPoint.Y - CenterEllipse.Height/2, 0, 0);
            CenterEllipse.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
            CenterEllipse.ManipulationCompleted += CenterEllipse_ManipulationCompleted;
            CenterEllipse.ManipulationDelta += CenterEllipse_ManipulationDelta;

            CenterEllipse.Children.Add(CenterEllipseVisual);

            CenterEllipse.Visibility = Visibility.Collapsed;
            BooCanvas.Children.Add(CenterEllipse);
        }


        void InitLine()
        {
            Curve = new Shapes.Polyline();
            Curve.Stroke = new SolidColorBrush(this.curveElement.LineColor);
            Curve.StrokeThickness = this.curveElement.BorderWidth;
            Curve.PointerPressed += Curve_PointerPressed;
            Curve.PointerReleased += Curve_PointerReleased;
        }

        void Curve_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            if (System.DateTime.Now.Ticks - PressedTicks < GlobalVariable.ShowMenuTime && Manipulationed == false)
            {
                if(this.curveMenu!=null)
                    this.curveMenu.ShowMenu();
            }
                Manipulationed = false;
        }

        void Curve_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            PressedTicks = System.DateTime.Now.Ticks;
            Manipulationed = false;
        }

        public Point GetBezierPoint(double t, Point startPoint, Point anchor, Point endPoint)
        {
            double x = (1 - t) * (1 - t) * startPoint.X + 2 * (1 - t) * t * anchor.X + t * t * endPoint.X;
            double y = (1 - t) * (1 - t) * startPoint.Y + 2 * (1 - t) * t * anchor.Y + t * t * endPoint.Y;
            Point point = new Point();
            point.X = x;
            point.Y = y;
            return point;
        }

        public Point InitBezierLine(Shapes.Polyline line,Point p1,Point p2,Point p3)
        {
            line.Points.Clear();
            Point p = new Point();
            line.Points.Add(p1);
            for (double i = 0; i <= 1; i += 0.01)
            {
                Point pt = GetBezierPoint(i, p1, p2, p3);
                line.Points.Add(pt);
                if (Math.Abs(i - 0.5) < 0.05)
                {
                    p.X = pt.X;
                    p.Y = pt.Y;
                }
            }
            line.Points.Add(p3);

            return p;
        }

        void InitFindCurve()
        {
            FindCurve = new Shapes.Polyline();
            FindCurve.Stroke = new SolidColorBrush(Colors.Transparent);
            FindCurve.StrokeThickness = 20;
            FindCurve.PointerPressed += Curve_PointerPressed;
            FindCurve.PointerReleased += Curve_PointerReleased;
                
            InitBezierLine(FindCurve,this.curveElement.Point1,this.curveElement.Point2,this.curveElement.Point3);
        }

        void InitCanvas()
        {
            BooCanvas = new Controls.Canvas();
            BooCanvas.Width = curveElement.ElementTransform.Width;
            BooCanvas.Height = curveElement.ElementTransform.Height;
        }

        void InitLineControlPanel()
        {
            lineControlPanel = new ControlPanel();
            LineStyle lineStyle = new LineStyle();

            lineControlPanel.AddTab(LanguageManager.StyleTabNormal2, LanguageManager.StyleTabDown2, LanguageManager.StyleTabDown2, lineStyle);

        }

        public override void GotFocus()
        {
            base.GotFocus();
            Focus.FocusElls.middle_top_ell.Visibility = Visibility.Collapsed;
            Focus.FocusElls.right_top_ell.Visibility = Visibility.Collapsed;
            Focus.FocusElls.right_middle_ell.Visibility = Visibility.Collapsed;
            Focus.FocusElls.middle_bottom_ell.Visibility = Visibility.Collapsed;
            Focus.FocusElls.left_middle_ell.Visibility = Visibility.Collapsed;
            Focus.FocusElls.left_bottom_ell.Visibility = Visibility.Collapsed;
            Focus.FocusElls.ScopeRectangle.Visibility = Visibility.Collapsed;
            Focus.FocusElls.rotate_ell.Visibility = Visibility.Collapsed;
            CenterEllipse.Visibility = Visibility.Visible;
            ShowLineControlPanel(this);
        }

        public override void LostFocus()
        {
            base.LostFocus();
            CenterEllipse.Visibility = Visibility.Collapsed;
            this.curveMenu.HideMenu();
            HideLineControlPanel();            
        }

        public void ShowLineControlPanel(IStyleController lineController)
        {
            if (lineControlPanel != null)
            {
                lineControlPanel.ShowControlPanel(lineController);
            }
        }

        public void HideLineControlPanel()
        {
            if (lineControlPanel != null)
            {
                lineControlPanel.HideControlPanel();
            }
        }

        public override void LoadFromElement(BooElement booElement)
        {
            base.LoadFromElement(booElement);
            base.InitializeActionMap(BooCanvas);
            centerPoint=InitBezierLine(Curve, this.curveElement.Point1, this.curveElement.Point2, this.curveElement.Point3);
            InitBezierLine(FindCurve, this.curveElement.Point1, this.curveElement.Point2, this.curveElement.Point3);
            if (topT != null)
            {
                topT.X = curveElement.Point1.X;
                topT.Y = curveElement.Point1.Y;
            }
            if (bottomT != null)
            {
                bottomT.X = curveElement.Point3.X;
                bottomT.Y = curveElement.Point3.Y;
            }
            Focus.FocusElls.left_top_ell.Margin = new Thickness(-FocusEllipses.FocusTouchAreaLength / 2, -FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
            Focus.FocusElls.right_bottom_ell.Margin = new Thickness(-FocusEllipses.FocusTouchAreaLength / 2, -FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
            CenterEllipse.Margin = new Thickness(centerPoint.X - FocusEllipses.FocusTouchAreaLength / 2, centerPoint.Y - FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
            Ellipse visual = (CenterEllipse.Children.First() as Ellipse);
            Random ran = new Random();
            double add = ran.NextDouble() * 0.1;
            visual.Margin = new Thickness((CenterEllipse.Width - visual.Width) / 2 + add, (CenterEllipse.Height - visual.Height) / 2, 0, 0);
            ApplyStyleChange();
        }

        public override void ApplyShapeChange()
        {
            centerPoint = InitBezierLine(Curve, this.curveElement.Point1, this.curveElement.Point2, this.curveElement.Point3);
            InitBezierLine(FindCurve, this.curveElement.Point1, this.curveElement.Point2, this.curveElement.Point3);
            if (topT != null)
            {
                topT.X = curveElement.Point1.X;
                topT.Y = curveElement.Point1.Y;
            }
            if (bottomT != null)
            {
                bottomT.X = curveElement.Point3.X;
                bottomT.Y = curveElement.Point3.Y;
            }
            Focus.FocusElls.left_top_ell.Margin = new Thickness(-FocusEllipses.FocusTouchAreaLength / 2, -FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
            Focus.FocusElls.right_bottom_ell.Margin = new Thickness(-FocusEllipses.FocusTouchAreaLength / 2, -FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
            if (CenterEllipse != null)
            {
                CenterEllipse.Margin = new Thickness(centerPoint.X - FocusEllipses.FocusTouchAreaLength / 2, centerPoint.Y - FocusEllipses.FocusTouchAreaLength / 2, 0, 0);
                Ellipse visual = (CenterEllipse.Children.First() as Ellipse);
                Random ran = new Random();
                double add = ran.NextDouble() * 0.1;
                visual.Margin = new Thickness((CenterEllipse.Width - visual.Width) / 2 + add, (CenterEllipse.Height - visual.Height) / 2, 0, 0);
            }
        }


        void CenterEllipse_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
        {
            RedoUndoHelper.SaveStatus(this);
            e.Handled = true;
        }

        void CenterEllipse_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            this.curveElement.Point2 = new Point(this.curveElement.Point2.X + e.Delta.Translation.X,
                this.curveElement.Point2.Y + e.Delta.Translation.Y);
            curveElement.PropertyChange("Shape");
            e.Handled = true;
        }

        public void left_top_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            double width = e.Delta.Translation.X;
            double height = e.Delta.Translation.Y;

            this.curveElement.Point1 = new Point(this.curveElement.Point1.X + width, this.curveElement.Point1.Y + height);
            this.curveElement.Point2 = new Point(this.curveElement.Point2.X+width/2, this.curveElement.Point2.Y+height/2);

            curveElement.PropertyChange("Shape");
            e.Handled = true;
        }

        public void right_bottom_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            BooCanvas.ManipulationMode = ManipulationModes.None;
            double width = e.Delta.Translation.X;
            double height = e.Delta.Translation.Y;

            this.curveElement.Point3 = new Point(this.curveElement.Point3.X + width, this.curveElement.Point3.Y + height);
            this.curveElement.Point2 = new Point(this.curveElement.Point2.X + width / 2, this.curveElement.Point2.Y + height / 2);

            BooCanvas.ManipulationMode = ManipulationModes.All;

            curveElement.PropertyChange("Shape");
            e.Handled = true;
        }

        public void left_top_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            RedoUndoHelper.SaveStatus(this);
            curveMenu.ShowMenu();
            e.Handled = true;
        }

        public void right_bottom_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            RedoUndoHelper.SaveStatus(this);
            curveMenu.ShowMenu();
            e.Handled = true;
        }

        public void middle_top_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
         
        }

        public void right_top_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void right_middle_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void middle_bottom_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void left_bottom_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void left_middle_ell_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void middle_top_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void right_top_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void right_middle_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }
      
        public void middle_bottom_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void left_bottom_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void left_middle_ell_ManipulationCompleted(object sender, Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void ChangeBorderColor(Windows.UI.Color color)
        {
            curveElement.LineColor = color;
            curveElement.PropertyChange("Style");
            RedoUndoHelper.SaveStatus(this);
        }

        public Windows.UI.Color GetBorderColor()
        {
            return ((SolidColorBrush)Curve.Stroke).Color;
        }

        public void ChangeBorderWidth(double width, bool isSave = false)
        {
            curveElement.BorderWidth = width;
            curveElement.PropertyChange("Style");
            if (isSave)
                RedoUndoHelper.SaveStatus(this);
        }

        public double GetBorderWidth()
        {
            return Curve.StrokeThickness;
        }

        public override BooLineBaseElement BooLineBaseElement
        {
            get { throw new NotImplementedException(); }
        }

        public override Point GetMenuDisplayPosition()
        {
            Point ret = new Point();
            double yLoc = 0;
            if (curveElement.Point1.Y < curveElement.Point3.Y)
            {
                yLoc = curveElement.Point1.Y;
            }
            else
            {
                yLoc = curveElement.Point3.Y;
            }
            yLoc += curveElement.ElementTransform.Translate.Y;

            double xLoc = (curveElement.Point1.X + curveElement.Point3.X) / 2 + curveElement.ElementTransform.Translate.X;
            return new Point(xLoc, yLoc);
        }

        public override void ApplyStyleChange()
        {
            Curve.Stroke = new SolidColorBrush(curveElement.LineColor);
            Curve.StrokeThickness = curveElement.BorderWidth;
        }

        public int GetZIndex()
        {
            return this.CurveElement.ElementTransform.ZIndex;
        }

        public void ChangeZIndexTo(int index)
        {
            this.CurveElement.ElementTransform.ZIndex = index;
        }


        public void rotate_ell_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void rotate_ell_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }


        public void rotate_ell_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }
    }
}
